package com.lin.demo.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lin.demo.annotations.Query;
import com.lin.demo.model.PageRequest;
import com.lin.demo.model.QueryObject;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;

@Slf4j
public class QueryHelp {
    public static <T, Q> QueryWrapper<T> getQueryWrapper(Q query) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (query == null) {
            return queryWrapper;
        }
        try {
            //1.得到查询类及其父类的所有字段
            List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
            for (Field field : fields) {
                boolean accessible = field.isAccessible();
                //2.设置对象的访问权限，保证对private属性的访问
                field.setAccessible(true);
                //3.获取Query注解
                Query annotation = field.getAnnotation(Query.class);
                if (annotation != null) {
                    String propName = annotation.propName();
                    String blurry = annotation.blurry();

                    String attributeName = StringUtils.isBlank(propName) ? camelToUnderline(field.getName()) : propName;
                    Object val = field.get(query);
                    // 是否需要排序
                    switch (annotation.order()) {
                        case ASC:
                            queryWrapper.orderByAsc(attributeName);
                            break;
                        case DESC:
                            queryWrapper.orderByDesc(attributeName);
                            break;
                        default:
                            break;
                    }
                    // 判断查询条件的属性是否为空，为空则不拼接查询条件
                    if (Objects.isNull(val) || "".equals(val)) {
                        continue;
                    }
                    // 模糊多字段
                    if (blurry != null && !"".equals(blurry)) {
                        String[] blurryArr = blurry.split(",");
                        for (String str : blurryArr) {
                            queryWrapper.like(str, val);
                        }
                        continue;
                    }
                    //4.根据注解拼接sql查询条件
                    switch (annotation.type()) {
                        case EQUAL:
                            queryWrapper.eq(attributeName, val);
                            break;
                        case GREATER_THAN:
                            queryWrapper.gt(attributeName, val);
                            break;
                        case GREATER_THAN_EQ:
                            queryWrapper.ge(attributeName, val);
                            break;
                        case LESS_THAN:
                            queryWrapper.lt(attributeName, val);
                            break;
                        case LESS_THAN_EQ:
                            queryWrapper.le(attributeName, val);
                            break;
                        case INNER_LIKE:
                            queryWrapper.like(attributeName, val);
                            break;
                        case LEFT_LIKE:
                            queryWrapper.likeLeft(attributeName, val);
                            break;
                        case RIGHT_LIKE:
                            queryWrapper.likeRight(attributeName, val);
                            break;
                        case IN:
                            queryWrapper.in(attributeName, (Collection<?>) val);
                            break;
                        case NOT_IN:
                            queryWrapper.notIn(attributeName, (Collection<?>) val);
                            break;
                        case NOT_EQUAL:
                            queryWrapper.ne(attributeName, val);
                            break;
                        case NOT_NULL:
                            queryWrapper.isNotNull(attributeName);
                            break;
                        case IS_NULL:
                            queryWrapper.isNull(attributeName);
                            break;
                        case BETWEEN:
                            List<Object> between = new ArrayList<>((List<?>) val);
                            if (between.size() != 2) {
                                break;
                            }
                            queryWrapper.between(attributeName, between.get(0), between.get(1));
                            break;
                        default:
                            break;
                    }
                }
                //5.还原对象访问权限
                field.setAccessible(accessible);
            }
        } catch (Exception exception) {
            log.error(exception.getMessage(), exception);
        }
        return queryWrapper;
    }

    /**
     * 将驼峰命名转化成下划线
     *
     * @param para para
     * @return 下划线 para
     */
    public static String camelToUnderline(String para) {
        StringBuilder sb = new StringBuilder(para);
        // 定位
        int temp = 0;
        // 从第2个字符开始 避免命名不规范
        for (int i = 1; i < para.length(); i++) {
            if (Character.isUpperCase(para.charAt(i))) {
                sb.insert(i + temp, "_");
                temp += 1;
            }
        }
        return sb.toString().toLowerCase();
    }

    /**
     * 获取类及其父类的所有字段对象
     *
     * @param clazz clazz
     * @param fields fields
     * @return fields
     */
    private static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
        if (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            getAllFields(clazz.getSuperclass(), fields);
        }
        return fields;
    }

    /**
     * @param pageRequest 前端分页对象
     * @param dClass      mybatis-plus表实体对象
     * @param <T>         分页查询泛型T
     * @param <D>         表实体泛型D
     * @return mybatis-plus分页查询对象
     */
    public static <T, D> Page<D> getPage(PageRequest<T> pageRequest, Class<D> dClass) throws Throwable {
        Constructor<D> declaredConstructor = dClass.getDeclaredConstructor();
        D d = declaredConstructor.newInstance();
        QueryWrapper<D> queryWrapper = QueryHelp.getQueryWrapper(new QueryObject());
        return new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
    }
}
